home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2000 / MacHack 2000.toast / pc / The Hacks / MacHacksBug / Python 1.5.2c1 / Extensions / Imaging / PIL / Image.py < prev    next >
Encoding:
Python Source  |  2000-06-23  |  22.4 KB  |  983 lines

  1. #
  2. # The Python Imaging Library.
  3. # $Id: Image.py,v 1.1.1.2 1999/01/13 09:40:19 sjoerd Exp $
  4. #
  5. # the Image class wrapper
  6. #
  7. # history:
  8. # 95-09-09 fl    Created
  9. # 96-03-11 fl    PIL release 0.0
  10. # 96-04-30 fl    PIL release 0.1b1
  11. # 96-05-27 fl    PIL release 0.1b2
  12. # 96-10-04 fl    PIL release 0.2a1
  13. # 96-11-04 fl    PIL release 0.2b1
  14. # 96-12-08 fl    PIL release 0.2b2
  15. # 96-12-16 fl    PIL release 0.2b3
  16. # 97-01-14 fl    PIL release 0.2b4
  17. # 97-06-02 fl    PIL release 0.3a1
  18. # 97-08-27 fl    PIL release 0.3a2
  19. # 98-02-02 fl    PIL release 0.3a3
  20. # 98-03-16 fl    PIL release 0.3a4
  21. # 98-07-02 fl    PIL release 0.3b1
  22. # 98-07-17 fl    PIL release 0.3b2
  23. # 99-01-01 fl    PIL release 1.0b1
  24. #
  25. # Copyright (c) Secret Labs AB 1997-99.
  26. # Copyright (c) Fredrik Lundh 1995-97.
  27. #
  28. # See the README file for information on usage and redistribution.
  29. #
  30.  
  31. VERSION = "1.0b1"
  32.  
  33. class _imaging_not_installed:
  34.     # module placeholder
  35.     def __getattr__(self, id):
  36.     raise ImportError, "The _imaging C module is not installed"
  37.  
  38. try:
  39.     # If the _imaging C module is not present, you can only use the
  40.     # "open" function to identify files.  Note that other modules
  41.     # should not refer to _imaging directly; import Image and use the
  42.     # Image.core variable instead.
  43.     import _imaging
  44.     core = _imaging
  45.     del _imaging
  46. except ImportError:
  47.     core = _imaging_not_installed()
  48.  
  49. import ImagePalette
  50. import os, string
  51.  
  52. # type stuff
  53. from types import IntType, StringType, TupleType
  54.  
  55. def isStringType(t):
  56.     return type(t) is StringType
  57.  
  58. def isTupleType(t):
  59.     return type(t) is TupleType
  60.  
  61. def isImageType(t):
  62.     return hasattr(t, "im")
  63.  
  64. from operator import isNumberType, isSequenceType
  65.  
  66. #
  67. # Debug level
  68.  
  69. DEBUG = 0
  70.  
  71. #
  72. # Constants (also defined in _imagingmodule.c!)
  73.  
  74. NONE = 0
  75.  
  76. # transpose
  77. FLIP_LEFT_RIGHT = 0
  78. FLIP_TOP_BOTTOM = 1
  79. ROTATE_90 = 2
  80. ROTATE_180 = 3
  81. ROTATE_270 = 4
  82.  
  83. # transforms
  84. AFFINE = 0
  85. EXTENT = 1
  86. PERSPECTIVE = 2 # Not yet implemented
  87. QUAD = 3
  88. MESH = 4
  89.  
  90. # resampling
  91. NONE = 0
  92. NEAREST = 0
  93. ANTIALIAS = 1 # Not yet implemented
  94. BILINEAR = 2
  95. BICUBIC = 3
  96.  
  97. # dithers
  98. NONE = 0
  99. NEAREST = 0
  100. ORDERED = 1 # Not yet implemented
  101. RASTERIZE = 2 # Not yet implemented
  102. FLOYDSTEINBERG = 3 # default
  103.  
  104. # palettes/quantizers
  105. WEB = 0
  106. ADAPTIVE = 1
  107.  
  108. # categories
  109. NORMAL = 0
  110. SEQUENCE = 1
  111. CONTAINER = 2
  112.  
  113. # --------------------------------------------------------------------
  114. # Registries
  115.  
  116. ID = []
  117. OPEN = {}
  118. MIME = {}
  119. SAVE = {}
  120. EXTENSION = {}
  121.  
  122. # --------------------------------------------------------------------
  123. # Modes supported by this version
  124.  
  125. _MODEINFO = {
  126.  
  127.     # official modes
  128.     "1": ("L", "L", ("1",)),
  129.     "L": ("L", "L", ("L",)),
  130.     "I": ("L", "I", ("I",)),
  131.     "F": ("L", "F", ("F",)),
  132.     "P": ("RGB", "L", ("P",)),
  133.     "RGB": ("RGB", "L", ("R", "G", "B")),
  134.     "RGBX": ("RGB", "L", ("R", "G", "B", "X")),
  135.     "RGBA": ("RGB", "L", ("R", "G", "B", "A")),
  136.     "CMYK": ("RGB", "L", ("C", "M", "Y", "K")),
  137.     "YCbCr": ("RGB", "L", ("Y", "Cb", "Cr")),
  138.  
  139.     # experimental modes
  140.     "I;16": ("L", "I", ("I",)),
  141.     "I;16B": ("L", "I", ("I",)),
  142.  
  143. }
  144.  
  145. MODES = _MODEINFO.keys()
  146. MODES.remove("I;16")
  147. MODES.remove("I;16B")
  148. MODES.sort()
  149.  
  150. def getmodebase(mode):
  151.     return _MODEINFO[mode][0]
  152.  
  153. def getmodetype(mode):
  154.     return _MODEINFO[mode][1]
  155.  
  156. def getmodebands(mode):
  157.     return len(_MODEINFO[mode][2])
  158.  
  159. # --------------------------------------------------------------------
  160. # Helpers
  161.  
  162. _initialized = 0
  163.  
  164. def preinit():
  165.     "Load standard file format drivers."
  166.  
  167.     global _initialized
  168.     if _initialized >= 1:
  169.     return
  170.  
  171.     for m in ("BmpImagePlugin", "GifImagePlugin", "JpegImagePlugin",
  172.               "PpmImagePlugin", "TiffImagePlugin"):
  173.         try:
  174.             __import__(m)
  175.         except ImportError:
  176.             pass # ignore missing driver for now
  177.  
  178.     _initialized = 1
  179.  
  180. def init():
  181.     "Load all file format drivers."
  182.  
  183.     global _initialized
  184.     if _initialized >= 2:
  185.     return
  186.  
  187.     import os, sys
  188.  
  189.     # only check directories (including current, if present in the path)
  190.     for path in filter(os.path.isdir, sys.path):
  191.     for file in os.listdir(path):
  192.         if file[-14:] == "ImagePlugin.py":
  193.         p, f = os.path.split(file)
  194.         f, e = os.path.splitext(f)
  195.         try:
  196.             sys.path.insert(0, path)
  197.             try:
  198.             __import__(f)
  199.             finally:
  200.             del sys.path[0]
  201.         except ImportError:
  202.             if DEBUG:
  203.             print "Image: failed to import",
  204.             print f, ":", sys.exc_value
  205.  
  206.     if OPEN or SAVE:
  207.     _initialized = 2
  208.  
  209.  
  210. # --------------------------------------------------------------------
  211. # Codec factories (used by tostring/fromstring and ImageFile.load)
  212.  
  213. def _getdecoder(mode, decoder_name, args, extra = ()):
  214.  
  215.     # tweak arguments
  216.     if args is None:
  217.     args = ()
  218.     elif type(args) != TupleType:
  219.     args = (args,)
  220.  
  221.     try:
  222.     # get decoder
  223.     decoder = getattr(core, decoder_name + "_decoder")
  224.     # print decoder, (mode,) + args + extra
  225.     return apply(decoder, (mode,) + args + extra)
  226.     except AttributeError:
  227.     raise IOError, "decoder %s not available" % decoder_name
  228.  
  229. def _getencoder(mode, encoder_name, args, extra = ()):
  230.  
  231.     # tweak arguments
  232.     if args is None:
  233.     args = ()
  234.     elif type(args) != TupleType:
  235.     args = (args,)
  236.  
  237.     try:
  238.     # get encoder
  239.     encoder = getattr(core, encoder_name + "_encoder")
  240.     # print encoder, (mode,) + args + extra
  241.     return apply(encoder, (mode,) + args + extra)
  242.     except AttributeError:
  243.     raise IOError, "encoder %s not available" % encoder_name
  244.  
  245.  
  246. # --------------------------------------------------------------------
  247. # Simple expression analyzer
  248.  
  249. class _E:
  250.     def __init__(self, data): self.data = data
  251.     def __coerce__(self, other): return self, _E(other)
  252.     def __add__(self, other): return _E((self.data, "__add__", other.data))
  253.     def __mul__(self, other): return _E((self.data, "__mul__", other.data))
  254.  
  255. def _getscaleoffset(expr):
  256.     stub = ["stub"]
  257.     data = expr(_E(stub)).data
  258.     try:
  259.         (a, b, c) = data # simplified syntax
  260.         if (a is stub and b == "__mul__" and isNumberType(c)):
  261.             return c, 0.0
  262.         if (a is stub and b == "__add__" and isNumberType(c)):
  263.             return 1.0, c
  264.     except TypeError: pass
  265.     try:
  266.         ((a, b, c), d, e) = data # full syntax
  267.         if (a is stub and b == "__mul__" and isNumberType(c) and
  268.             d == "__add__" and isNumberType(e)):
  269.             return c, e
  270.     except TypeError: pass
  271.     raise ValueError, "illegal expression"
  272.  
  273.  
  274. # --------------------------------------------------------------------
  275. # Implementation wrapper
  276.  
  277. import os
  278.  
  279. class Image:
  280.  
  281.     format = None
  282.     format_description = None
  283.  
  284.     def __init__(self):
  285.     self.im = None
  286.     self.mode = ""
  287.     self.size = (0,0)
  288.     self.palette = None
  289.     self.info = {}
  290.     self.category = NORMAL
  291.  
  292.     def __setattr__(self, id, value):
  293.     if id == "palette":
  294.         pass # print "set", id, value
  295.     self.__dict__[id] = value
  296.  
  297.     def _makeself(self, im):
  298.     new = Image()
  299.     new.im = im
  300.     new.mode = im.mode
  301.     new.size = im.size
  302.     new.palette = self.palette
  303.     new.info = self.info
  304.     return new
  305.  
  306.     def _dump(self, file = None):
  307.         import tempfile
  308.     if not file:
  309.         file = tempfile.mktemp()
  310.     self.load()
  311.     self.im.save_ppm(file)
  312.     return file
  313.  
  314.     def tostring(self, encoder_name = "raw", *args):
  315.     "Return image as a binary string"
  316.  
  317.         # may pass tuple instead of argument list
  318.         if len(args) == 1 and isTupleType(args[0]):
  319.             args = args[0]
  320.  
  321.     if encoder_name == "raw" and args == ():
  322.         args = self.mode
  323.  
  324.         self.load()
  325.  
  326.         # unpack data
  327.         e = _getencoder(self.mode, encoder_name, args)
  328.         e.setimage(self.im)
  329.  
  330.         data = []
  331.         while 1:
  332.             l, s, d = e.encode(65536)
  333.             data.append(d)
  334.             if s:
  335.                 break
  336.         if s < 0:
  337.             raise RuntimeError, "encoder error %d in tostring" % s
  338.  
  339.         return string.join(data, "")
  340.  
  341.     def tobitmap(self, name = "image"):
  342.     "Return image as an XBM bitmap"
  343.  
  344.     self.load()
  345.     if self.mode != "1":
  346.         raise ValueError, "not a bitmap"
  347.         data = self.tostring("xbm")
  348.     return string.join(["#define %s_width %d\n" % (name, self.size[0]),
  349.         "#define %s_height %d\n"% (name, self.size[1]),
  350.         "static char %s_bits[] = {\n" % name, data, "};"], "")
  351.  
  352.     def fromstring(self, data, decoder_name = "raw", *args):
  353.         "Load data to image from binary string"
  354.  
  355.         # may pass tuple instead of argument list
  356.         if len(args) == 1 and isTupleType(args[0]):
  357.             args = args[0]
  358.  
  359.     # default format
  360.     if decoder_name == "raw" and args == ():
  361.         args = self.mode
  362.  
  363.         # unpack data
  364.         d = _getdecoder(self.mode, decoder_name, args)
  365.         d.setimage(self.im)
  366.         s = d.decode(data)
  367.  
  368.     if s[0] >= 0:
  369.             raise ValueError, "not enough image data"
  370.     if s[1] != 0:
  371.             raise ValueError, "cannot decode image data"
  372.  
  373.     def load(self, modify=0):
  374.     if self.im and self.palette and self.palette.rawmode:
  375.         self.im.putpalette(self.palette.rawmode, self.palette.data)
  376.             self.palette.mode = "RGB"
  377.             self.palette.rawmode = None
  378.             if self.info.has_key("transparency"):
  379.                 self.im.putpalettealpha(self.info["transparency"], 0)
  380.                 self.palette.mode = "RGBA"
  381.  
  382.     #
  383.     # function wrappers
  384.  
  385.     def convert(self, mode=None, data=None, dither=None,
  386.         palette=WEB, colors=256):
  387.         "Convert to other pixel format"
  388.  
  389.     if not mode:
  390.         # determine default mode
  391.         if self.mode == "P":
  392.         mode = self.palette.mode
  393.         else:
  394.         return self.copy()
  395.  
  396.     self.load()
  397.  
  398.     if data:
  399.         # matrix conversion
  400.         if mode not in ("L", "RGB"):
  401.         raise ValueError, "illegal conversion"
  402.         im = self.im.convert_matrix(mode, data)
  403.         return self._makeself(im)
  404.  
  405.     if mode == "P" and palette == ADAPTIVE:
  406.         im = self.im.quantize(colors)
  407.         return self._makeself(im)
  408.  
  409.     # colourspace conversion
  410.     if dither is None:
  411.         dither = FLOYDSTEINBERG
  412.  
  413.     try:
  414.         im = self.im.convert(mode, dither)
  415.     except ValueError:
  416.         try:
  417.         # normalize source image and try again
  418.         im = self.im.convert(getmodebase(self.mode))
  419.         im = im.convert(mode, dither)
  420.         except KeyError:
  421.         raise ValueError, "illegal conversion"
  422.  
  423.     return self._makeself(im)
  424.  
  425.     def quantize(self, colours=256, method=0, kmeans=0):
  426.  
  427.     # methods: 
  428.     #    0 = median cut
  429.     #    1 = maximum coverage
  430.  
  431.         # NOTE: this functionality will be moved to the extended
  432.     # quantizer interface in a later versions of PIL.
  433.  
  434.     self.load()
  435.     im = self.im.quantize(colours, method, kmeans)
  436.     return self._makeself(im)
  437.  
  438.     def copy(self):
  439.         "Copy raster data"
  440.  
  441.     self.load()
  442.     im = self.im.copy()
  443.     return self._makeself(im)
  444.  
  445.     def crop(self, box = None):
  446.         "Crop region from image"
  447.  
  448.     self.load()
  449.     if box is None:
  450.         return self.copy()
  451.  
  452.         # delayed operation
  453.         return _ImageCrop(self, box)
  454.  
  455.     def draft(self, mode, size):
  456.         "Configure image decoder"
  457.  
  458.     pass
  459.  
  460.     def filter(self, kernel):
  461.         "Apply environment filter to image"
  462.  
  463.     if self.mode == "P":
  464.         raise ValueError, "cannot filter palette images"
  465.     self.load()
  466.     id = kernel.id
  467.     if self.im.bands == 1:
  468.         return self._makeself(self.im.filter(id))
  469.     # fix to handle multiband images since _imaging doesn't
  470.     ims = []
  471.     for c in range(self.im.bands):
  472.         ims.append(self._makeself(self.im.getband(c).filter(id)))
  473.     return merge(self.mode, ims)
  474.  
  475.     def getbands(self):
  476.     "Get band names"
  477.  
  478.     return _MODEINFO[self.mode][2]
  479.  
  480.     def getbbox(self):
  481.     "Get bounding box of actual data (non-zero pixels) in image"
  482.  
  483.         self.load()
  484.     return self.im.getbbox()
  485.  
  486.     def getdata(self, band = None):
  487.     "Get image data as sequence object."
  488.  
  489.         self.load()
  490.     if band is not None:
  491.         return self.im.getband(band)
  492.     return self.im # could be abused
  493.  
  494.     def getextrema(self):
  495.     "Get min/max value"
  496.  
  497.         self.load()
  498.     return self.im.getextrema()
  499.  
  500.     def getpixel(self, xy):
  501.     "Get pixel value"
  502.  
  503.         self.load()
  504.     return self.im.getpixel(xy)
  505.  
  506.     def getprojection(self):
  507.     "Get projection to x and y axes"
  508.  
  509.         self.load()
  510.     x, y = self.im.getprojection()
  511.     return map(ord, x), map(ord, y)
  512.  
  513.     def histogram(self, mask=None, extrema=None):
  514.         "Take histogram of image"
  515.  
  516.     self.load()
  517.     if mask:
  518.         mask.load()
  519.         return self.im.histogram((0, 0), mask.im)
  520.     if self.mode in ("I", "F"):
  521.         if extrema is None:
  522.         extrema = self.getextrema()
  523.         return self.im.histogram(extrema)
  524.     return self.im.histogram()
  525.  
  526.     def offset(self, xoffset, yoffset = None):
  527.         "Offset image in horizontal and/or vertical direction"
  528.  
  529.     if yoffset is None:
  530.         yoffset = xoffset
  531.     self.load()
  532.     return self._makeself(self.im.offset(xoffset, yoffset))
  533.  
  534.     def paste(self, im, box = None, mask = None):
  535.         "Paste other image into region"
  536.  
  537.     if box is None:
  538.         # all of image
  539.         box = (0, 0) + self.size
  540.  
  541.         if not isImageType(im):
  542.             if len(box) == 2:
  543.                 box = box + self.size
  544.             im = new(self.mode, (box[2]-box[0], box[3]-box[1]), im)
  545.  
  546.     elif len(box) == 2:
  547.         # lower left corner given
  548.         box = box + (box[0]+im.size[0], box[1]+im.size[1])
  549.  
  550.         im.load()
  551.     self.load(1)
  552.  
  553.     # fix to handle conversion when pasting (should be
  554.     # done via adapters)
  555.     if self.mode != im.mode:
  556.         im = im.convert(self.mode)
  557.  
  558.     if mask:
  559.         mask.load()
  560.         self.im.paste(im.im, box, mask.im)
  561.     else:
  562.         self.im.paste(im.im, box)
  563.  
  564.     def point(self, lut, mode = None):
  565.         "Map image through lookup table"
  566.  
  567.         if self.mode in ("I", "F"):
  568.             # floating point; lut must be a valid expression
  569.             scale, offset = _getscaleoffset(lut)
  570.             self.load()
  571.             im = self.im.point_transform(scale, offset);
  572.         else:
  573.             # integer image; use lut and mode
  574.             self.load()
  575.             if not isSequenceType(lut):
  576.                 # if it isn't a list, it should be a function
  577.                 lut = map(lut, range(256)) * self.im.bands
  578.             im = self.im.point(lut, mode)
  579.  
  580.     return self._makeself(im)
  581.  
  582.     def putalpha(self, im):
  583.         "Set alpha layer"
  584.  
  585.     if self.mode != "RGBA" or im.mode not in ("1", "L"):
  586.         raise ValueError, "illegal image mode"
  587.  
  588.     im.load()
  589.     self.load(1)
  590.  
  591.     if im.mode == "1":
  592.         im = im.convert("L")
  593.  
  594.     self.im.putband(im.im, 3)
  595.  
  596.     def putdata(self, data, scale = 1.0, offset = 0.0):
  597.     "Put data from a sequence object into an image."
  598.  
  599.     self.load(1) # hmm...
  600.     self.im.putdata(data, scale, offset)
  601.  
  602.     def putpalette(self, data, rawmode = "RGB"):
  603.     "Put palette data into an image."
  604.  
  605.         if self.mode not in ("L", "P"):
  606.             raise ValueError, "illegal image mode"
  607.         if type(data) != StringType:
  608.             data = string.join(map(chr, data), "")
  609.         self.mode = "P"
  610.         self.palette = ImagePalette.raw(rawmode, data)
  611.         self.palette.mode = "RGB"
  612.  
  613.     def putpixel(self, xy, value):
  614.     "Set pixel value"
  615.  
  616.         self.load(1)
  617.     return self.im.putpixel(xy, value)
  618.  
  619.     def resize(self, size, resample = NEAREST):
  620.         "Resize image"
  621.  
  622.     if resample not in (NEAREST, BILINEAR, BICUBIC):
  623.         raise ValueError, "unknown resampling filter"
  624.  
  625.     self.load()
  626.     im = self.im.resize(size, resample)
  627.     return self._makeself(im)
  628.  
  629.     def rotate(self, angle, resample = NEAREST):
  630.         "Rotate image.  Angle given as degrees counter-clockwise."
  631.  
  632.     if resample not in (NEAREST, BILINEAR, BICUBIC):
  633.         raise ValueError, "unknown resampling filter"
  634.  
  635.     self.load()
  636.     im = self.im.rotate(angle, resample)
  637.     return self._makeself(im)
  638.  
  639.     def save(self, fp, format = None, **params):
  640.         "Save image to file or stream"
  641.  
  642.     if isStringType(fp):
  643.         import __builtin__
  644.         filename = fp
  645.             fp = __builtin__.open(fp, "wb")
  646.             close = 1
  647.     else:
  648.         filename = ""
  649.             close = 0
  650.  
  651.     self.encoderinfo = params
  652.     self.encoderconfig = ()
  653.  
  654.     self.load()
  655.  
  656.     preinit()
  657.  
  658.         ext = string.lower(os.path.splitext(filename)[1])
  659.  
  660.         try:
  661.  
  662.             if not format:
  663.                 format = EXTENSION[ext]
  664.  
  665.         SAVE[string.upper(format)](self, fp, filename)
  666.  
  667.     except KeyError, v:
  668.  
  669.             init()
  670.  
  671.             if not format:
  672.                 format = EXTENSION[ext]
  673.  
  674.             SAVE[string.upper(format)](self, fp, filename)
  675.  
  676.         if close:
  677.             fp.close()
  678.  
  679.     def seek(self, frame):
  680.         "Seek to given frame in sequence file"
  681.  
  682.         if frame != 0:
  683.             raise EOFError
  684.  
  685.     def show(self, title = None):
  686.         "Display image (for debug purposes only)"
  687.  
  688.     try:
  689.         import ImageTk
  690.         ImageTk._show(self, title)
  691.         # note: caller must enter mainloop
  692.     except:
  693.         _showxv(self, title)
  694.  
  695.     def split(self):
  696.         "Split image into bands"
  697.  
  698.         ims = []
  699.     self.load()
  700.     for i in range(self.im.bands):
  701.         ims.append(self._makeself(self.im.getband(i)))
  702.     return tuple(ims)
  703.  
  704.     def tell(self):
  705.         "Return current frame number"
  706.  
  707.         return 0
  708.  
  709.     def thumbnail(self, size):
  710.     "Create thumbnail representation (modifies image in place)"
  711.  
  712.     # preserve aspect ratio
  713.     x, y = self.size
  714.     if x > size[0]: y = y * size[0] / x; x = size[0]
  715.     if y > size[1]: x = x * size[1] / y; y = size[1]
  716.     size = x, y
  717.  
  718.     if size == self.size:
  719.         return
  720.  
  721.     self.draft(None, size)
  722.  
  723.     self.load(1)
  724.  
  725.     im = self.resize(size)
  726.  
  727.     self.im = im.im
  728.     self.mode = im.mode
  729.     self.size = size
  730.  
  731.     def transform(self, size, method, data, resample=NEAREST, fill=1):
  732.         "Transform image"
  733.  
  734.     im = new(self.mode, size, None)
  735.     if method == MESH:
  736.         # list of quads
  737.         for box, quad in data:
  738.         im.__transformer(box, self, QUAD, quad, resample, fill)
  739.     else:
  740.         im.__transformer((0, 0)+size, self, method, data, resample, fill)
  741.  
  742.     return im
  743.  
  744.     def __transformer(self, box, image, method, data,
  745.               resample=NEAREST, fill=1):
  746.     "Transform into current image"
  747.  
  748.     # FIXME: this should be turned into a lazy operation (?)
  749.  
  750.     w = box[2]-box[0]
  751.     h = box[3]-box[1]
  752.  
  753.     if method == AFFINE:
  754.         # change argument order to match implementation
  755.         data = (data[2], data[0], data[1], 
  756.             data[5], data[3], data[4])
  757.     elif method == EXTENT:
  758.         # convert extent to an affine transform
  759.         x0, y0, x1, y1 = data
  760.         xs = float(x1 - x0) / w
  761.         ys = float(y1 - y0) / h
  762.         method = AFFINE
  763.         data = (x0 + xs/2, xs, 0, y0 + ys/2, 0, ys)
  764.     elif method == QUAD:
  765.         # quadrilateral warp.  data specifies the four corners
  766.         # given as NW, SW, SE, and NE.
  767.         nw = data[0:2]; sw = data[2:4]; se = data[4:6]; ne = data[6:8]
  768.         x0, y0 = nw; As = 1.0 / w; At = 1.0 / h
  769.         data = (x0, (ne[0]-x0)*As, (sw[0]-x0)*At,
  770.             (se[0]-sw[0]-ne[0]+x0)*As*At,
  771.             y0, (ne[1]-y0)*As, (sw[1]-y0)*At,
  772.             (se[1]-sw[1]-ne[1]+y0)*As*At)
  773.     else:
  774.         raise ValueError, "unknown transformation method"
  775.  
  776.     if resample not in (NEAREST, BILINEAR, BICUBIC):
  777.         raise ValueError, "unknown resampling filter"
  778.  
  779.     image.load()
  780.  
  781.     self.load(1)
  782.     self.im.transform2(box, image.im, method, data, resample, fill)
  783.  
  784.     def transpose(self, method):
  785.         "Transpose image (flip or rotate in 90 degree steps)"
  786.  
  787.     self.load()
  788.     im = self.im.transpose(method)
  789.     return self._makeself(im)
  790.  
  791.  
  792. # --------------------------------------------------------------------
  793. # Delayed operations
  794.  
  795. class _ImageCrop(Image):
  796.  
  797.     def __init__(self, im, box):
  798.  
  799.     Image.__init__(self)
  800.  
  801.         self.mode = im.mode
  802.         self.size = box[2]-box[0], box[3]-box[1]
  803.  
  804.         self.__crop = box
  805.  
  806.         self.im = im.im
  807.  
  808.     def load(self, modify=0):
  809.         
  810.         # delayed evaluation of crop operation
  811.  
  812.         if self.__crop is None:
  813.             return
  814.  
  815.     # FIXME: the C implementation of crop is broken, so we
  816.         # implement it by pasting into empty image instead.
  817.  
  818.     # im = self.im.__crop(self.__crop)
  819.  
  820.     im = core.new(self.mode, self.size)
  821.  
  822.     im.paste(self.im, (-self.__crop[0], -self.__crop[1],
  823.          self.im.size[0]-self.__crop[0],
  824.          self.im.size[1]-self.__crop[1]))
  825.  
  826.     if self.mode == "P":
  827.         im.putpalette("RGB", self.im.getpalette())
  828.  
  829.         self.im = im
  830.  
  831.         self.__crop = None
  832.  
  833.  
  834. # --------------------------------------------------------------------
  835. # Factories
  836.  
  837. #
  838. # Debugging
  839.  
  840. def _wedge():
  841.     "Create greyscale wedge (for debugging only)"
  842.  
  843.     return Image()._makeself(core.wedge("L"))
  844.  
  845. #
  846. # Create/open images.
  847.  
  848. def new(mode, size, color = 0):
  849.     "Create a new image"
  850.  
  851.     if color is None:
  852.     # don't initialize
  853.     return Image()._makeself(core.new(mode, size))
  854.  
  855.     return Image()._makeself(core.fill(mode, size, color))
  856.  
  857.  
  858. def fromstring(mode, size, data, decoder_name = "raw", *args):
  859.     "Load image from string"
  860.  
  861.     # may pass tuple instead of argument list
  862.     if len(args) == 1 and isTupleType(args[0]):
  863.         args = args[0]
  864.  
  865.     if decoder_name == "raw" and args == ():
  866.         args = mode
  867.  
  868.     im = new(mode, size)
  869.     im.fromstring(data, decoder_name, args)
  870.     return im
  871.  
  872. def open(fp, mode = "r"):
  873.     "Open an image file, without loading the raster data"
  874.  
  875.     if mode != "r":
  876.         raise ValueError, "bad mode"
  877.  
  878.     if isStringType(fp):
  879.         import __builtin__
  880.     filename = fp
  881.         fp = __builtin__.open(fp, "rb")
  882.     else:
  883.         filename = ""
  884.  
  885.     prefix = fp.read(16)
  886.  
  887.     preinit()
  888.  
  889.     for i in ID:
  890.     try:
  891.         factory, accept = OPEN[i]
  892.         if not accept or accept(prefix):
  893.         fp.seek(0)
  894.         return factory(fp, filename)
  895.     except SyntaxError:
  896.         pass
  897.  
  898.     init()
  899.  
  900.     for i in ID:
  901.     try:
  902.         factory, accept = OPEN[i]
  903.         if not accept or accept(prefix):
  904.         fp.seek(0)
  905.         return factory(fp, filename)
  906.     except SyntaxError:
  907.         pass
  908.  
  909.     raise IOError, "cannot identify image file"
  910.  
  911. #
  912. # Image processing.
  913.  
  914. def blend(im1, im2, alpha):
  915.     "Interpolate between images."
  916.  
  917.     if alpha == 0.0:
  918.     return im1
  919.     elif alpha == 1.0:
  920.     return im2
  921.     return Image()._makeself(core.blend(im1.im, im2.im, alpha))
  922.  
  923. def composite(image1, image2, mask):
  924.     "Create composite image by blending images using a transparency mask"
  925.  
  926.     image = image2.copy()
  927.     image.paste(image1, None, mask)
  928.     return image
  929.  
  930. def eval(image, *args):
  931.     "Evaluate image expression"
  932.  
  933.     return image.point(args[0])
  934.  
  935. def merge(mode, bands):
  936.     "Merge a set of single band images into a new multiband image."
  937.  
  938.     if getmodebands(mode) != len(bands) or "*" in mode:
  939.         raise ValueError, "wrong number of bands"
  940.     for im in bands[1:]:
  941.         if im.mode != getmodetype(mode) or im.size != bands[0].size:
  942.             raise ValueError, "wrong number of bands"
  943.     im = core.new(mode, bands[0].size)
  944.     for i in range(getmodebands(mode)):
  945.     bands[i].load()
  946.     im.putband(bands[i].im, i)
  947.     return Image()._makeself(im)
  948.  
  949. # --------------------------------------------------------------------
  950. # Plugin registry
  951.  
  952. def register_open(id, factory, accept = None):
  953.     id = string.upper(id)
  954.     ID.append(id)
  955.     OPEN[id] = factory, accept
  956.  
  957. def register_mime(id, mimetype):
  958.     MIME[string.upper(id)] = mimetype
  959.  
  960. def register_save(id, driver):
  961.     SAVE[string.upper(id)] = driver
  962.  
  963. def register_extension(id, extension):
  964.     EXTENSION[string.lower(extension)] = string.upper(id)
  965.  
  966.  
  967. # --------------------------------------------------------------------
  968. # Unix display support
  969.  
  970. def _showxv(self, title = None):
  971.  
  972.     if self.mode == "P":
  973.     file = self.convert("RGB")._dump()
  974.     else:
  975.     file = self._dump()
  976.  
  977.     if title:
  978.     opt = "-name \"%s\"" % title
  979.     else:
  980.     opt = ""
  981.  
  982.     os.system("(xv %s %s; rm -f %s)&" % (opt, file, file))
  983.